NestJS의 Guard는 강력한 보안 및 인증 기능을 제공하며, 사용자 정의 Guard를 통해 액세스 제어를 구현할 수 있습니다. 이번 글에서는 “RolesGuard”라는 사용자 정의 Guard를 구현하면서 겪은 경험을 공유하고자 합니다.

1. RolesGuard 개발 시작하기

우선, “RolesGuard”를 개발하기 위해 새로운 Guard 클래스를 생성합니다. Guard 클래스는 @nestjs/common 모듈에서 제공하는 CanActivate 인터페이스를 구현해야 합니다. 이를 통해 Guard가 요청의 액세스를 허용 또는 거부하는 로직을 구현할 수 있습니다.

import { CanActivate, ExecutionContext, Injectable } from "@nestjs/common";

@Injectable()
export class RolesGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    // 액세스 제어 로직을 구현합니다.
    // ...
  }
}

2. RolesGuard에 Role 기반 인가 로직 추가하기

이제 “RolesGuard”의 canActivate 메서드 내에서 Role 기반 인가 로직을 추가합니다. 여기서는 @Roles 데코레이터를 사용하여 엔드포인트에 필요한 Role 정보를 설정하고, @nestjs/core 모듈에서 제공하는 Reflector를 사용하여 해당 Role 정보를 추출합니다.

import { CanActivate, ExecutionContext, Injectable } from "@nestjs/common";
import { Reflector } from "@nestjs/core";

@Injectable()
export class RolesGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const roles = this.reflector.get<string[]>("roles", context.getHandler());
    if (!roles) {
      return true; // @Roles 애노테이션이 없는 경우, 인가 통과
    }

    const request = context.switchToHttp().getRequest();
    const user = request.user;
    const userRoles = user.roles; // 사용자의 역할 정보 (예: user.roles)

    const hasRole = userRoles.some((role) => roles.includes(role));
    return hasRole; // 역할 확인 결과 반환
  }
}

3. @Roles 데코레이터 생성하기

“RolesGuard”에서 Role 기반 인가를 수행하기 위해 @Roles 데코레이터를 생성합니다. 이 데코레이터는 엔드포인트 또는 컨트롤러에 필요한 Role 정보를 설정할 수 있도록 도와줍니다.

import { SetMetadata } from "@nestjs/common";

export const Roles = (...roles: string[]) => SetMetadata("roles", roles);

4. Guard 적용하기

마지막으로, “JwtAuthGuard”와 “RolesGuard”를 함께 사용하여 인증과 인가를 동시에 처리합니다. 엔드포인트 또는 컨트롤러에 @UseGuards(JwtAuthGuard, RolesGuard)를 추가하고, @Roles 데코레이터를 사용하여 필요한 Role 정보를 설정합니다.

import { Controller, Get, UseGuards } from "@nestjs/common";
import { JwtAuthGuard } from "./guards/jwt-auth.guard";
import { RolesGuard } from "./guards/roles.guard";

@Controller("example")
export class ExampleController {
  @Get()
  @UseGuards(JwtAuthGuard, RolesGuard)
  someRoute() {
    // ...
  }
}

위의 예시에서 @UseGuards(JwtAuthGuard, RolesGuard)를 사용하여 "JwtAuthGuard"와 "RolesGuard"를 동시에 적용하고 있습니다. 이를 통해 요청이 들어올 때 먼저 "JwtAuthGuard"가 JWT 인증을 처리하고 사용자 정보를 추출한 후, "RolesGuard"가 역할 기반의 인가를 수행하게 됩니다.

“JwtAuthGuard”와 “RolesGuard”를 함께 사용하여 인증과 인가를 처리함으로써 NestJS 애플리케이션의 보안 수준을 높일 수 있습니다. 필요한 역할을 가진 사용자만이 허용된 리소스에 액세스할 수 있도록 보장합니다.

마무리

위의 단계를 따라가면 NestJS에서 Role-based 인가를 위한 사용자 정의 Guard를 개발할 수 있습니다. “RolesGuard”는 @Roles 데코레이터를 통해 설정된 Role 정보를 기반으로 인가를 수행하며, 엔드포인트 또는 컨트롤러에 @UseGuards(RolesGuard)를 추가하여 Guard를 적용할 수 있습니다.

Role 기반 인가를 구현함으로써 애플리케이션의 보안 수준을 높일 수 있으며, 필요한 역할을 가진 사용자만이 허용된 리소스에 액세스할 수 있게 됩니다.

이 글을 통해 NestJS에서 Role-based 인가를 구현하는 방법을 익히고, 애플리케이션의 보안을 강화할 수 있기를 바랍니다.